<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta http-equiv="Cache-Control" content="no-siteapp">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=1, minimum-scale=1, maximum-scale=1">
<meta name="referrer" content="never">
<meta name="robots" content="index,follow">
<link rel="shortcut icon" href="/favicon.png?v=198964">
<link rel="apple-itouch-icon" href="/favicon.png?v=198964">
<link href="/bundle/index.min.css" rel="stylesheet">
<link href="https://fonts.loli.net/css?family=Merriweather:300,700,700italic,300italic|Open+Sans:700,400" rel="stylesheet">
<link href="https://cdn.staticfile.org/prism/1.16.0/themes/prism.min.css" rel="stylesheet">
<link href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<script>
    function ensureDate(e){return"object"!=typeof e&&(e=new Date(e)),e}function dateFormat(e,t){void 0===t&&(t=e,e=ensureDate());let n={M:(e=ensureDate(e)).getMonth()+1,d:e.getDate(),h:e.getHours(),m:e.getMinutes(),s:e.getSeconds(),q:Math.floor((e.getMonth()+3)/3),S:e.getMilliseconds()},r=new RegExp("([yMdhmsqS])+","g");return t=t.replace(r,function(t,r){let u=n[r];if(void 0!==u)return t.length>1&&(u=(u="0"+u).substring(u.length-2)),u;if("y"===r){return(e.getFullYear()+"").substring(4-t.length)}return t})}
</script>
    <meta name="keywords" content="吼啊! Vue2.4组件间通信新姿势,Vue,">
    <meta name="description" content="吼啊! Vue2.4组件间通信新姿势,Vue,">
    <meta name="author" content="江矿先森.">
    <title>吼啊! Vue2.4组件间通信新姿势</title>
    <link href="/bundle/iconfont.css" rel="stylesheet">
    <link href="/bundle/reward.css" rel="stylesheet">
    <script src='/bundle/av.min.js'></script>
    <script src='/bundle/valine.min.js'></script>
</head>

<body>
    <article class="container">
        <header class="header-wrap asset">
    <nav class="main-nav">
        <ul class="menu vertical naive">
            <li class="menu-item"><a href="/">Home</a></li>
            <li class="menu-item"><a href="/archive.html">Archive</a></li>
            <li class="menu-item"><a href="/tag.html">Tag</a></li>
            
            <li class="menu-item"><a href="/atom.xml">RSS</a></li>
        </ul>
    </nav>
    <div class="bgs" style="background-image: url(https://pic6.58cdn.com.cn/nowater/webim/big/n_v212fe49b1d6d5492cb1def84eeff4b142.jpg);"></div>
    <div class="vertical">
        <div class="header-wrap-content inner">
            <h3 class="title">Stay before every beautiful thoughts.</h3>
            <h3 class="subtitle">Just be nice, always think twice!</h3>
        </div>
    </div>
</header>
        <article class="main article">
            <h1 class="title">吼啊! Vue2.4组件间通信新姿势</h1>
            <section class="info">
                <span class="avatar" style="background-image: url(https://pic1.58cdn.com.cn/nowater/webim/big/n_v2a9773b605e754c8493cf53ca8f5c0d7e.jpg);"></span> <a class="name" href="javascript:;">江矿先森.</a> 
                <span class="date"><script>document.write(dateFormat( 1507865034 *1000, 'yyyy-MM-dd'))</script></span> 
                <span class="tags"><a class="tages" href="/tag/Vue/index.html">Vue</a></span>
            </section>
            <article class="content"><p>Vue应用在组件化之后，通常存在着 父子组件、兄弟组件、跨级组件 等组件关系，那么组件之间如何进行通信；Vue2.4提供了两种新的组件通讯方法。</p>

<p>在 Vue 中，父子组件的关系可以总结为 props down、events up。</p>

<ul>
<li>父子组件通信 ：父组件通过 props 向下传递数据给子组件</li>

<li><p>子父组件通信 ：子组件通过 events 给父组件发送消息</p>

<ul>
<li>使用 $on(eventName) 监听事件</li>
<li>使用 $emit(eventName) 触发事件</li>
</ul></li>

<li><p>非父子组件通信 ：使用一个空的 Vue 实例作为中央事件总线</p></li>
</ul>

<p>在Vue 2.4 版本引入了组件通讯的新方式。</p>

<h4>1. 重新引入 .sync 修饰符</h4>

<p>熟悉 Vue1.x 的朋友一定对 .sync 修饰器并不陌生。在Vue1.x 中我们可能会需要对一个 prop 进行『双向绑定』。当一个 子组件 改变了一个 prop的值时，这个变化也会 同步到父组件中 所绑定的值。</p>

<p>因为它破坏了『单向数据流』的假设， .sync 在2.0版本被移除，引起了广泛的讨论。在2.3.0版本 .sync 又回来了，不过与1.x不同。</p>

<p>这次只是原有语法的语法糖(syntax sugar)包装而成，其背后实现原理是，在组件上自动扩充一个额外的 v-on 监听器：</p>

<p>代码如下：</p>

<pre><code class="language-html">&lt;comp:foo.sync=&quot;bar&quot;&gt;&lt;/comp&gt;
</code></pre>

<p>会被扩充为：</p>

<pre><code class="language-html">&lt;child:bar=&quot;foo&quot;@update:bar=&quot;e =&gt; foo = e&quot;&gt;
</code></pre>

<p>对于子组件，如果想要更新 foo 的值，则需要显式地触发一个事件，而不是直接修改 prop：</p>

<pre><code class="language-js">this.$emit('update:bar', newValue)
</code></pre>

<h4>2. $attrs 与 $listeners</h4>

<p>多级组件嵌套需要传递数据时，通常使用的方法是通过vuex。如果仅仅是传递数据，而不做中间处理，使用 vuex 处理，未免有点杀鸡用牛刀。Vue 2.4 版本提供了另一种方法，使用 v-bind=”$attrs”, 将父组件中不被认为 props特性绑定的属性传入子组件中，通常配合 interitAttrs 选项一起使用。</p>

<ul>
<li>2.1 interitAttrs</li>
</ul>

<p>在版本 2.4 之前，默认情况下父作用域的不被作为props特性绑定的属性，将会作为普通的 HTML 属性，应用在跟元素上。</p>

<pre><code class="language-html"> // parent.vue
&lt;template&gt;
    &lt;child-commpent:foo=&quot;f&quot;:boo=&quot;b&quot;&gt;&lt;/child-comment&gt;
&lt;/template&gt;

&lt;script&gt;
const childComment = ()=&gt; import('./childCom.vue')
export default {
    data () {
      return {
        f: 'Hello world!'
        b: 'Hello Vue!'
      }  
    }
}
&lt;/script&gt;
</code></pre>

<pre><code class="language-html">// childComment.vue
&lt;template&gt;
    &lt;div&gt;{{ foo }}&lt;div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
    props: ['foo'] //父作用域的boo不被作为props绑定
}
&lt;/script&gt;
</code></pre>

<p>//boo会作为普通的 HTML 属性，应用在跟元素上。</p>

<pre><code class="language-html">&lt;div boo=&quot;Hello Vue!&quot;&gt;Hello world!&lt;/div&gt;
```html
设置 interitAttrs 为 false，之后，不会应用到跟元素上。
```html
// childCom.vue
&lt;template&gt;
    &lt;div&gt;{{ foo }}&lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
  export default {
    props: ['foo'],
    inheritAttrs: false
  }
&lt;/script&gt;
</code></pre>

<p>//boo会作为普通的 HTML 属性，应用在跟元素上。</p>

<pre><code class="language-html">&lt;div&gt;Hello world!&lt;/div&gt;
</code></pre>

<ul>
<li>2.2 $attrs, $listeners</li>
</ul>

<p>在Vue 2.4 版本,配合 interitAttrs选项， 父组件中未被props(v-on)绑定的属性(事件) 可以在子组件中，通过 $attrs ， $listeners 获取。</p>

<pre><code class="language-html">// demo.vue
  &lt;template&gt;
    &lt;div&gt;
      &lt;child-com:foo=&quot;foo&quot;:boo=&quot;boo&quot;:coo=&quot;coo&quot;:doo=&quot;doo&quot;&gt;&lt;/child-com&gt;
    &lt;/div&gt;
  &lt;/tempalte&gt;
  &lt;script&gt;
  const childCom = ()=&gt; import('./childCom1.vue')
  export default {
    data () {
      return {
        foo: 'Hello World!',
        boo: 'Hello Javascript!',
        coo: 'Hello Vue',
        doo: 'Last'
      }
    },
    components: { childCom }
  }
  &lt;/script&gt;
</code></pre>

<pre><code class="language-html">// childCom1.vue
&lt;template&gt;
  &lt;div&gt;
    &lt;p&gt;foo: {{ foo }}&lt;/p&gt;
    &lt;p&gt;attrs: {{ $attrs }}&lt;/p&gt;
    &lt;child-com2v-bind=&quot;$attrs&quot;&gt;&lt;/child-com2&gt;
  &lt;/div&gt;
&lt;/template&gt;
&lt;script&gt;
const childCom2 = ()=&gt; import('./childCom2.vue')
export default {
  props: ['foo'],  // foo作为props属性绑定
  inheritAttrs: false,
  created () {
    console.log(this.$attrs) // { boo: 'Hello Javascript!', coo: 'Hello Vue', doo: 'Last' }
  }
}
&lt;/script&gt;
</code></pre>

<pre><code class="language-html">// childCom2.vue
&lt;template&gt;
  &lt;div&gt;
   &lt;p&gt;boo: {{ boo }}&lt;/p&gt;
   &lt;p&gt;attrs: {{ $attrs }}&lt;/p&gt;
   &lt;child-com3v-bind=&quot;$attrs&quot;&gt;&lt;/child-com3&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
const childCom3 = ()=&gt; import('./childCom3.vue')
export default {
  props: ['boo'] // boo作为props属性绑定
  inheritAttrs: false,
  created () {
    console.log(this.$attrs) // { coo: 'Hello Vue', doo: 'Last' }
  }
}
&lt;/script&gt;
</code></pre>

<h4>小结</h4>

<p>在Vue2.0被移除的 .sync 被重新加入到2.4版本，不同的是需要显式地触发一个事件，而不是直接修改 prop。
Vue2.4提供了 $attrs , $listeners 来传递数据与事件，跨级组件之间的通讯变得更简单。</p>
</article>
            <section class="author">
                
                <div class="avatar" style="background-image: url(https://pic1.58cdn.com.cn/nowater/webim/big/n_v2a9773b605e754c8493cf53ca8f5c0d7e.jpg);"></div>
                <a class="name" href="javascript:;">江矿先森.</a>
                <div class="intro">前(台)端(菜), 喜欢瞎折腾新技术. 乜野都识少少, 先可以扮代表.</div>
            </section>
            <section class="social">
                <a href="https://github.com/joname1" target="_blank">
                    <i class="iconfont i-github"></i>
                </a>
                <a href="javascript:alert('你电脑中了不知名的病毒, 并抛出了警告 atob(“d3hJZDogam9uYW1lLmxpYW5ndGFu”)')" target="_blank">
                    <i class="iconfont i-wechat"></i>
                </a>
                <a href="https://www.zhihu.com/people/joname-liangtan" target="_blank">
                    <i class="iconfont i-zhihu"></i>
                </a>
                <a href="javascript:alert('对方不想跟你讲话, 并向你扔来一段乱码 atob(“am9uYW1lLmxpYW5ndGFuQGdtYWlsLmNvbQ”)')" target="_blank">
                    <i class="iconfont i-email"></i>
                </a>
            </section>

            <div class="reward">
                <div class="reward-button">赏
                    <span class="reward-code">
                        <span class="alipay-code">
                            <img class="alipay-img wdp-appear" src="https://pic1.58cdn.com.cn/nowater/webim/big/n_v24d5eae197a764eb194b61e366ff263ba.jpg"><b>支付宝扫码</b>
                        </span>
                    <span class="wechat-code">
                            <img class="wechat-img wdp-appear" src="https://pic1.58cdn.com.cn/nowater/webim/big/n_v20ec7ae162f6a4219b8d0b429a2dbc9b3.jpg"><b>微信扫码</b>
                        </span>
                    </span>
                </div>
                
                <p class="reward-notice">如果文章对你有帮助, 扫上方二维码请我喝杯奶茶吧 :p</p>
            </div>

            <div id="comment"></div>
            
        </article>
    </article>
    <footer class="footer clearfix">
    <span class="copyright">
        <script>
            document.write(new Date().getFullYear());
        </script> <i class="fa fa-copyright"></i> Made with <i class="fa fa-heart"></i> using &ltjoname /&gt
        <span id="runtime_span"></span>
    </span>
</footer>
    <script src="/bundle/index.min.js"></script>
    <script src="https://cdn.staticfile.org/prism/1.16.0/prism.min.js"></script>
    <script>
        new Valine({el: '#comment',appId: 'PieJ3iHvVTJ9C5yBudK6sxaT-MdYXbMMI',appKey: 'Yt25unM4vc9wzBvC2lL20Frc',placeholder: 'ヾﾉ≧∀≦)o来啊, 快活啊, 反正有大把时光!!',path: window.location.pathname,avatar: 'retro',pageSize: 10,guest_info: ['nick', 'mail'],lang: 'en'});
    </script>
</body>

</html>